import {
  Component,
  ElementRef,
  Renderer2,
  Inject,
  OnInit,
  OnDestroy,
  HostListener,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input,
  Output,
  EventEmitter, AfterViewInit,
} from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { DOCUMENT, LocationStrategy } from '@angular/common';
import { Subscription } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
import { MenuService, SettingsService, Menu } from '@core';

import { Nav } from './interface';
import PinyinMatch from 'pinyin-match';
import { ApiService } from '@core/services/http/api.service';
import { UserAuthService } from '@core/services/user-auth.service';
import { deepClone } from '../../../utils/utils';
import { ButtonService } from '@core/services/button.service';


const SHOWCLS = 'nav-floating-show';
const FLOATINGCLS = 'nav-floating';

@Component({
  selector: 'sidebar-nav',
  templateUrl: './sidebar-nav.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  preserveWhitespaces: false,
})
export class SidebarNavComponent implements OnInit, OnDestroy, AfterViewInit {
  private rootEl: HTMLDivElement;
  /** @inner */
  floatingEl: HTMLDivElement;
  private bodyEl: HTMLBodyElement;
  list: Nav[];
  queryList: any = [];
  visible: boolean = false;
  private change$: Subscription;
  isLoading: boolean = true;
  text: string;
  searchList: any = [];
  querySearchList: any = [];
  searchTitle: string = '请输入关键词';
  pinData: any[] = [];
  showPinData: any[] = [];

  @Input() autoCloseUnderPad = true;

  @Output() select = new EventEmitter<Menu>();

  @Input() set menuIn(value: any) {
    this.list = [];
    if (value) {
      for (let item of value.children) {
        item['_open'] = true;
        this.toggleOpen(item);
      }
      this.list.push(value);
    }
    // setTimeout(()=>{
    this.getPushPin();
    // },500);
  }

  get menuIn() {
    return this.list;
  }

  constructor(
    // private initService:InitService,
    private menuSrv: MenuService,
    public settings: SettingsService,
    private router: Router,
    private locationStrategy: LocationStrategy,
    private render: Renderer2,
    private cd: ChangeDetectorRef,
    private api: ApiService,
    private userAuthService: UserAuthService,
    private buttonService: ButtonService,
    @Inject(DOCUMENT) private doc: any,
    el: ElementRef,
  ) {
    this.rootEl = el.nativeElement as HTMLDivElement;
  }

  ngOnInit() {
    //this.initService.loadAppData();
    this.bodyEl = this.doc.querySelector('body');
    this.menuSrv.openedByUrl(this.router.url);
    this.genFloatingContainer();
    // this.isLoading = this.menuSrv.loading;
    this.change$ = <any>this.menuSrv.change.subscribe(res => {
      this.list = res;
      this.searchList = res;
      this.getPushPin();
      this.cd.detectChanges();
      // this.isLoading = this.menuSrv.loading;
      // setTimeout(()=>{
      //   this.isLoading = false;
      // },100);
      // console.log(this.list);
    });
    this.installUnderPad();
    // console.log(this.list)
  }

  ngAfterViewInit() {
    this.isLoading = false;
    // this.isLoading = true;
  }

  private floatingAreaClickHandle(e: MouseEvent) {
    e.stopPropagation();
    e.preventDefault();
    const linkNode = e.target as Element;
    if (linkNode.nodeName !== 'A' && linkNode.nodeName !== 'SPAN') {
      return false;
    }
    let href = linkNode.nodeName == 'A' ? 'href' : 'link';

    let url: string = linkNode.getAttribute(href);
    if (url && url.startsWith('#')) {
      url = url.slice(1);
    }
    // 如果配置了bashHref 则去掉baseHref
    const baseHerf = this.locationStrategy.getBaseHref();
    if (baseHerf) {
      url = url.slice(baseHerf.length);
    }
    let item = this.menuSrv.getPathByUrl(url).pop();
    if (linkNode.nodeName == 'A') {
      this.router.navigateByUrl(url);
      this.onSelect(item);
    } else if (linkNode.nodeName == 'SPAN') {
      this.pushPin(item);
    }

    this.hideAll();
    return false;
  }

  clearFloatingContainer() {
    if (!this.floatingEl) return;
    this.floatingEl.removeEventListener(
      'click',
      this.floatingAreaClickHandle.bind(this),
    );
    // fix ie: https://github.com/cipchk/delon/issues/52
    if (this.floatingEl.hasOwnProperty('remove')) {
      this.floatingEl.remove();
    } else if (this.floatingEl.parentNode) {
      this.floatingEl.parentNode.removeChild(this.floatingEl);
    }
  }

  genFloatingContainer() {
    this.clearFloatingContainer();
    this.floatingEl = this.render.createElement('div');
    this.floatingEl.classList.add(FLOATINGCLS + '-container');
    this.floatingEl.addEventListener(
      'click',
      this.floatingAreaClickHandle.bind(this),
      false,
    );
    this.bodyEl.appendChild(this.floatingEl);
  }

  private genSubNode(linkNode: HTMLLinkElement, item: Nav): HTMLUListElement {
    const id = `_sidebar-nav-${item.__id}`;
    const node = linkNode.nextElementSibling.cloneNode(
      true,
    ) as HTMLUListElement;
    node.id = id;
    node.classList.add(FLOATINGCLS);
    node.addEventListener(
      'mouseleave',
      () => {
        node.classList.remove(SHOWCLS);
      },
      false,
    );
    this.floatingEl.appendChild(node);
    return node;
  }

  private hideAll() {
    const allNode = this.floatingEl.querySelectorAll('.' + FLOATINGCLS);
    for (let i = 0; i < allNode.length; i++) {
      allNode[i].classList.remove(SHOWCLS);
    }
  }

  // calculate the node position values.
  private calPos(linkNode: HTMLLinkElement, node: HTMLUListElement) {
    const rect = linkNode.getBoundingClientRect();
    // bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14721015/
    const scrollTop = Math.max(
      this.doc.documentElement.scrollTop,
      this.bodyEl.scrollTop,
    );
    const top = rect.top + scrollTop;
    const left = rect.right + 5;
    node.style.top = `${top}px`;
    node.style.left = `${left}px`;
  }

  showSubMenu(e: MouseEvent, item: Nav) {
    // if (this.settings.layout.collapsed !== true) {
    //   return;
    // }
    e.preventDefault();
    const linkNode = e.target as Element;
    this.genFloatingContainer();
    const subNode = this.genSubNode(linkNode as HTMLLinkElement, item);
    this.hideAll();
    subNode.classList.add(SHOWCLS);
    this.calPos(linkNode as HTMLLinkElement, subNode);
  }

  onSelect(item: Menu, type = 'menu') {
    // console.log(item)
    const code = item.groupType.code;
    if (code === 'app') {
      // this.code = '/app'+ item.link;
      window.open('/app' + item.link, '_self');
    } else {
      // this.code = item.link;
      this.router.navigateByUrl(item.link);
      this.buttonService.getMenuLog(item.link, type);
    }
    // this.code = code == 'app' ? '/app'+ item.link : item.link;
    this.visible = false;
    this.text = item.text;
    setTimeout(() => {
      this.getPushPin();
    }, 500);
    this.select.emit(item);
    // this.hideMenu();

    if(type != 'common'){
      let parent = this.getItemNode(item);
      this.list = [];
      parent['_open'] = true;
      for (let item of parent.children) {
        item._open = item._open != 'node';
        this.toggleOpen(item);
      }
      this.list.push(parent);
    }

  }

  getItemNode(item) {
    let parent;
    item['_open'] = 'node';
    if (item.hasOwnProperty('__parent') && item.__parent) {
      parent = this.getItemNode(item.__parent);
    } else {
      parent = item;
    }
    return parent;
  }


  getPushPin() {
    let userInfo = this.userAuthService.getUserInfoObj();
    let postId = userInfo.userAccount.post.id;

    let terminal = this.userAuthService.getTerminal();
    let api = 'aut.user.getPersonalMenuMarks';
    let setData = {
      'post': { 'id': postId },
      'terminal': terminal,
    };
    this.api.post(api, setData).subscribe((body) => {
      // console.log('getPin', body);
      this.pinData = [];
      this.pinData = body;
      this.showPinData = [];
      // const list = deepClone(this.list);
      // this.list = []
      this.checkPin(this.list, this.pinData);
      // this.list = list
      // console.log('showPin', this.showPinData);
      // console.log('list', this.list);
      this.cd.detectChanges();
    });
  }

  updatePushPin(item) {
    let userInfo = this.userAuthService.getUserInfoObj();
    let postId = userInfo.userAccount.post.id;
    let api = 'aut.user.savePersonalMenuMarks';
    let setData = {
      'menu': {
        'id': item.id,
      },
      'mark': item.pushpin,
      'post': {
        'id': postId,
      },
    };
    this.api.post(api, setData).subscribe((body) => {
      // console.log('updatePin', body);
      // this.pinData =  body;
      this.getPushPin();
    });
  }

  checkPin(list: Menu[], pinData) {
    for (const item of list) {
      if (item.children && item.children.length > 0) {
        this.checkPin(item.children, pinData);
      } else if (item.hasOwnProperty('pushpin')) {
        let check = false;
        for (const pin of pinData) {
          if (pin.id == item.id) {
            check = true;
          }
        }
        if (check) {
          this.showPinData.push(item);
        }
        item.pushpin = check;
      }
    }
  }

  pushPin(item: Menu) {
    // console.log('钉钉', item);
    if (!item.hasOwnProperty('pushpin')) {
      item['pushpin'] = true;
    }
    item.pushpin = !item.pushpin;
    this.updatePushPin(item);
  }

  toggleOpen(item: Nav) {
    // this.menuSrv.visit((i, p) => {
    //   if (i !== item) i._open = false;
    // });
    // let pItem = item.__parent;
    // while (pItem) {
    //   pItem._open = true;
    //   pItem = pItem.__parent;
    // }
    // this.text = item.children[0].text;
    // this.router.navigateByUrl(item.children[0].link);
    // if(!item.hasOwnProperty('_open')){
    //   item._open = false;
    // }else{
    item._open = !item._open;
    // }
    this.cd.markForCheck();
  }

  @HostListener('document:click', ['$event.target'])
  onClick() {
    this.hideAll();
  }

  ngOnDestroy(): void {
    this.change$.unsubscribe();
    if (this.route$) this.route$.unsubscribe();
    this.clearFloatingContainer();
  }

  // region: Under pad

  private route$: Subscription;

  private installUnderPad() {
    if (!this.autoCloseUnderPad) return;
    this.route$ = <any>this.router.events
      .pipe(filter(e => e instanceof NavigationEnd))
      .subscribe(s => this.underPad());
    this.underPad();
  }

  private underPad() {
    if (window.innerWidth < 992 && !this.settings.layout.collapsed) {
      this.settings.setLayout('collapsed', true);
    }
  }

  onKeyUp(param) {
    let value = param.target.value.toLowerCase();
    this.queryList = [];
    this.querySearchList = [];
    if (value) {
      this.queryMenuList(this.searchList, value);
    }
  }

  queryMenuList(data, value) {
    data.map(d => {
      for (let key in d) {
        if (key == 'children') {
          this.queryMenuList(d[key], value);
        } else if (key == 'operations' && d['children'].length == 0) {
          if (PinyinMatch.match(d['text'], value)) {
            const text = '';
            d['search'] = this.queryMenu(d, text);
            this.querySearchList.push(d);
          }
        }
      }
    });
    if (this.querySearchList.lenght > 0) {
      this.searchTitle = '请输入关键词';
    } else {
      this.searchTitle = '搜索不到相关字段';
    }
    this.queryList = this.queryAfterData(this.querySearchList);
  }

  queryMenu(data, text) {
    if (data['__parent'] !== null) {
      if (text == '') {
        text = data['__parent'].text;
      } else {
        text = data['__parent'].text + ' > ' + text;
      }
      return this.queryMenu(data['__parent'], text);
    } else if (data['__parent'] === null) {
      return text;
    }
  }

  // 分组
  queryAfterData(resData) {
    let dataInfo = {};
    resData.forEach(item => {
      let { search } = item;
      if (!dataInfo[search]) {
        dataInfo[search] = {
          search,
          child: [],
        };
      }
      dataInfo[search].child.push(item);
    });
    let list = Object.values(dataInfo);
    return list;
  }


  hideMenu() {
    this.visible = false;
    const list = document.querySelector('.sidebar-menu-list');
    this.render.setStyle(list, 'display', 'none');
    setTimeout(() => {
      // this.render.setStyle(list, 'display', 'block');
      this.render.removeStyle(list, 'display');
    }, 1000);
  }

  showMenu(param) {
    let show = true;
    if (param.hasOwnProperty('combinationMenu')) {
      show = !param.combinationMenu;
    }
    return show;
  }


  // endregion
}
